package cn.iocoder.yudao.module.trade.service.order;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.module.digital.api.cardkeymanager.ICardKeyManagerApi;
import cn.iocoder.yudao.module.digital.api.cardkeymanager.dto.CardKeySecretDTO;
import cn.iocoder.yudao.module.esim.api.esasset.EsAssetApi;
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.product.enums.spu.DeliveryMethodEnum;
import cn.iocoder.yudao.module.product.enums.spu.DeliveryTypeEnum;
import cn.iocoder.yudao.module.product.enums.spu.ProductTypeEnum;
import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordDetailDTO;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderAuditStatusEnum;
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderDeliveryStatusEnum;
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Nullable;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

/**
 * 订单发货 Service 类
 *
 * @author cai
 * @date 2024/03/21 11:28
 */
@Slf4j
@Service
public class OrderDeliveryService {

    @Resource
    private ProductSpuApi productSpuApi;

    @Lazy
    @Resource
    private ICardKeyManagerApi cardKeyManagerApi;

    @Lazy
    @Resource
    private OrderMailService orderMailService;

    @Lazy
    @Resource
    private TradeOrderUpdateService tradeOrderUpdateService;

    @Resource
    private TradeOrderQueryService tradeOrderQueryService;

    @Resource
    private CombinationRecordApi combinationRecordApi;

    @Lazy
    @Resource
    private EsAssetApi esAssetApi;

    public void delivery(TradeOrderDO order, List<TradeOrderItemDO> orderItems) {
        // 1.如果不是拼团订单则判定是否需要发货
        if (!TradeOrderTypeEnum.isCombination(order.getType())) {
            List<ProductSpuRespDTO> spuList = check(order, orderItems);
            if (CollectionUtil.isEmpty(spuList)) {
                return;
            }
            log.info("[delivery][订单({}, orderNo: {}) 非拼团, 自动发货订单]", order.getId(), order.getNo());
            autoDelivery(order, orderItems, spuList);
        } else {
            // 2.拼团订单则更新订单项状态
            boolean success = combinationRecordApi.isCombinationRecordSuccess(order.getUserId(), order.getId());
            if (!success) {
                log.info("[delivery][订单({}, orderNo: {}) 拼团未完成, 暂不发货]", order.getId(), order.getNo());
                return;
            }
            log.info("[delivery][订单({}, orderNo: {}) 拼团完成, 开始发货]", order.getId(), order.getNo());
            TradeOrderDO headRecord = null;
            List<TradeOrderDO> memberRecords;
            Long headId;
            if (Objects.equals(order.getCombinationHeadId(), 0L)) { // 情况一：团长
                headId = order.getCombinationRecordId();
                headRecord = order;
                memberRecords = tradeOrderQueryService.getCombinationOrderList(headId);
            } else { // 情况二：团员
                headId = order.getCombinationHeadId();
                CombinationRecordDetailDTO combinationRecord = combinationRecordApi.queryById(headId);
                if (Objects.nonNull(combinationRecord)) {
                    headRecord = tradeOrderQueryService.getOrder(combinationRecord.getOrderId());
                } else {
                    log.warn("[delivery][团长拼团记录不存在, recordId: {}]", headId);
                }
                memberRecords = tradeOrderQueryService.getCombinationOrderList(headId);
            }
            List<TradeOrderDO> allRecords = new ArrayList<>(memberRecords.size() + 1);
            if (Objects.nonNull(headRecord)) {
                allRecords.add(headRecord);
            }
            allRecords.addAll(memberRecords);
            log.info("[delivery][拼团订单数: {}, 准备发货]", allRecords.size());
            for (TradeOrderDO tradeOrder : allRecords) {
                List<TradeOrderItemDO> items = tradeOrderQueryService.getOrderItemListByOrderId(tradeOrder.getId());
                List<ProductSpuRespDTO> spuList = check(tradeOrder, items);
                if (CollectionUtil.isEmpty(spuList)) {
                    continue;
                }
                log.info("[delivery][订单({}, orderNo: {}) 拼团单, 自动发货订单]", order.getId(), order.getNo());
                autoDelivery(tradeOrder, items, spuList);
            }
        }
    }

    /**
     * 自动发货
     * @param order 订单
     * @param orderItems 订单项
     * @param spuList 商品
     */
    private void autoDelivery(TradeOrderDO order, List<TradeOrderItemDO> orderItems, List<ProductSpuRespDTO> spuList) {
        Map<Long, Integer> productTypeMap = spuList.stream().collect(Collectors.toMap(ProductSpuRespDTO::getId, ProductSpuRespDTO::getProductType));
        //List<CardKeySecretDTO> secretList = new ArrayList<>();
        for (TradeOrderItemDO orderItem : orderItems) {
            Integer productType = productTypeMap.get(orderItem.getSpuId());
            if (ObjectUtil.equals(productType, ProductTypeEnum.GIFT_CARD.getValue())) {
                // 3.如果是礼品卡商品则领取卡密
                Integer nominalValue = orderItem.getNominalValue();
                if (!orderItem.getCustomDenomination()) {
                    nominalValue = null;
                }
                cardKeyManagerApi.claimCardKeySecret(order.getNo(), orderItem.getSkuId(), orderItem.getCount(), nominalValue);
                //secretList.addAll(secretDTOS);
            } else if (ObjectUtil.equals(productType, ProductTypeEnum.ESIM_CARD.getValue())) {
                // 4.如果是E-SIM卡
                // 调用第三方接口发货
                esAssetApi.createESim(order.getNo(), order.getUserId(), orderItem.getReceiveEmail());
            } else {
                log.warn("[autoDelivery][订单({}) 商品({}) 类型({}) 不支持]", order.getId(), orderItem.getSkuId(), productType);
            }
        }
        /*log.info("[autoDelivery][订单({}, orderNo: {}) 获取卡密数量: {}]", order.getId(), order.getNo(), secretList.size());
        // 发送邮件
        if (CollectionUtil.isNotEmpty(secretList)) {
            orderMailService.sendOrderCDKMail(order, orderItems, 1L, secretList);
        }
        tradeOrderUpdateService.updateOrderComplete(order.getId());*/
    }

    @Nullable
    private List<ProductSpuRespDTO> check(TradeOrderDO order, List<TradeOrderItemDO> orderItems) {
        boolean canDeliver = TradeOrderAuditStatusEnum.isPassed(order.getAuditStatus())
            && !TradeOrderDeliveryStatusEnum.hasDelivered(order.getDeliveryStatus())
            && ObjectUtil.equals(order.getDeliveryType(), DeliveryTypeEnum.NO_DELIVERY_NEEDED.getValue());
        if (!canDeliver) {
            log.info("[afterPayOrder][订单({}, orderNo: {}) 状态不是未发货]", order.getId(), order.getNo());
            return null;
        }
        AtomicBoolean flag = new AtomicBoolean(canDeliver);
        // 2.判断是否全部为虚拟商品
        Set<Long> spuIds = orderItems.stream().map(TradeOrderItemDO::getSpuId).collect(Collectors.toSet());
        List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(spuIds);
        spuList.stream().filter(v -> !v.getVirtualProduct()).findAny().ifPresent(v -> flag.set(false));
        if (!flag.get()) {
            log.info("[afterPayOrder][订单({}, orderNo: {}) 不是虚拟商品]", order.getId(), order.getNo());
            return null;
        }
        // 判断是否全部为自动发货
        orderItems.stream().filter(v -> !DeliveryMethodEnum.isAutomatic(v.getDeliveryMethod())).findAny().ifPresent(v -> flag.set(false));
        if (!flag.get()) {
            log.info("[afterPayOrder][订单({}, orderNo: {}) 不是自动发货]", order.getId(), order.getNo());
            return null;
        }
        return spuList;
    }

}
